#! coding:utf8
__author__ = 'Rusher'
import tkinter
import tkinter.messagebox as msgbox
import socket
import time
import threading
import sqlite3
import configparser


class ClientUI(tkinter.Frame):
    def __init__(self, master):
        tkinter.Frame.__init__(self, master)
        self.config = configparser.ConfigParser()
        if not self.config.read('client_config.ini'):
            self.save_info('10.128.39.135', 12345, '')

        self.username = self.config['info']['username']
        self.host = self.config['info']['host']
        self.port = int(self.config['info']['port'])

        self.master = master
        self.connection = socket.socket()
        self.s_msg = ''
        self.flags = {'error': False,
                      'restart': False}

        self.dialog_frame = tkinter.Frame(self, height=25)
        self.dialog_text = tkinter.Text(self.dialog_frame,
                                        font='Aria 12',
                                        height=23, width=90)
        self.dialog_scrollbar = tkinter.Scrollbar(self.dialog_frame,
                                                  command=self.dialog_text.yview)
        self.dialog_text.config(yscrollcommand=self.dialog_scrollbar.set)

        self.input_frame = tkinter.Frame(self)
        self.input_entry = tkinter.Text(self.input_frame, font='Aria 12', height=2, width=87,
                                        state=tkinter.DISABLED)

        def send_shortcut(event):
            send_msg_button()

        self.input_entry.bind('<Control-Return>', send_shortcut)

        def send_msg_button():
            s_msg = self.input_entry.get('1.0', tkinter.END)
            self.send_msg(s_msg)
            self.input_entry.delete('1.0', tkinter.END)

        self.send_button = tkinter.Button(self.input_frame,
                                          text="Send",
                                          command=send_msg_button)

    def save_info(self, host, port, username):
        self.config['info'] = {'host': host,
                               'port': port,
                               'username': username}
        with open('client_config.ini', 'w') as f:
            self.config.write(f)

    def start(self):
        self.grid()
        self.dialog_text.pack(side=tkinter.LEFT, expand=1, fill=tkinter.X)
        self.dialog_scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
        self.input_entry.grid(row=0, column=1)
        self.send_button.grid(row=0, column=20)

        self.dialog_frame.grid(row=0)
        self.input_frame.grid(row=1)

    def settings(self):
        self.master.title('设置')
        command_frame = tkinter.Frame(self.master)

        input_frame = tkinter.Frame(command_frame)
        input_frame.grid(row=0, column=0)

        tkinter.Label(input_frame, text='IP地址：').grid(row=0, column=0)
        host_entry = tkinter.Entry(input_frame)
        host_entry.insert(0, self.host)
        host_entry.grid(row=0, column=1)

        tkinter.Label(input_frame, text='端口号：').grid(row=1, column=0)
        port_entry = tkinter.Entry(input_frame)
        port_entry.insert(0, self.port)
        port_entry.grid(row=1, column=1)

        # setting descriptions
        doc_frame = tkinter.Frame(command_frame)
        doc_frame.grid(row=1, column=0)
        host_doc = tkinter.Label(doc_frame,
                                 text='host为服务器IP, 本地填localhost.'
                                      'port为端口号, 一般不必改. 用户名必须填.')
        host_doc.grid(row=0, column=0)

        tkinter.Label(input_frame, text='用户名：').grid(row=2, column=0)
        username_entry = tkinter.Entry(input_frame)
        if self.username == '':
            username_entry.insert(0, '用户名')
            delete = True
        else:
            username_entry.insert(0, self.username)
            delete = False
        username_entry.grid(row=2, column=1)

        def delete_entry(evnet):
            if delete:
                username_entry.delete(0, tkinter.END)
        username_entry.bind('<Button>', delete_entry)

        def start_button_func():
            self.host = host_entry.get()
            try:
                self.port = int(port_entry.get())
            except ValueError:
                self.error_box(message='端口号不合法')
                return None
            name = username_entry.get()
            if name in ('用户名', '', ' ') or ' ' in name:
                self.error_box(restart=False, error=False, message='请输入用户名\n用户名不能包含空格、空行')
                return None
            self.username = name
            command_frame.destroy()
            command_frame.quit()

        start_button = tkinter.Button(command_frame,
                                      text="确定",
                                      command=start_button_func)
        start_button.grid(row=2, column=0)
        command_frame.grid(row=2)
        command_frame.mainloop()

    def print_msg(self, r_msg=''):
        import tkinter, time
        msg = time.ctime() + '\n' + r_msg + '\n'
        self.dialog_text.config(state=tkinter.NORMAL)
        self.dialog_text.insert(tkinter.END, msg)
        self.dialog_text.config(state=tkinter.DISABLED)
        self.dialog_text.see(tkinter.END)

    def error_box(self, restart=True, error=True, title='错误', message=None):
        self.flags['restart'] = restart
        msgbox.showerror(title=title, message=message)
        self.flags['error'] = error

    def info_striped(self, s):
        if s.decode('utf8') in ('', ' ', '\n'):
            return None
        s = s.decode('utf8').strip()
        start = s[1:].find('!')
        info = s[1:start+1]
        content = s[start+2:]
        if info == 'error':
            if content == 'username_conflict':
                self.error_box(message='用户名已被占用')
                self.connection.close()
                return None
        elif info == 'info' and content == 'OK':
            print('OK')
            self.save_info(self.host, self.port, self.username)
        else:
            print(self.username + ' saved!')
            return info + ' <<< ' + content

    def connect_receive(self):
        print(threading.current_thread())
        self.connection.settimeout(4)
        try:
            self.connection.connect((self.host, self.port))
            print('Got connection from %s:%s' % (self.host, str(self.port)))
            self.print_msg('Got connection from %s:%s' % (self.host, str(self.port)))
            self.send_msg('!username!' + self.username, silent=True)      # send username 'silently'
        except socket.timeout:
            print('timeout')
            self.error_box(message='连接超时，请检查IP和端口号！')
            self.connection.close()
        except socket.gaierror:
            print('IP地址不合法，请重新输入')
            self.error_box(message='IP地址不合法，请重新输入')
            self.connection.close()
        self.connection.settimeout(None)
        while 1:
            if self.flags['error']:
                break
            print('Starting receiving...')
            self.input_entry.config(state=tkinter.NORMAL)

            try:
                print('trying')
                r_msg = self.connection.recv(1024)
                print('tried')
                striped_msg = self.info_striped(r_msg)
                if striped_msg:
                    print("\n<", striped_msg)
                    self.print_msg(striped_msg)
            except socket.error:
                print("\nClient Closed!")
                try:
                    self.connection.close()
                except OSError:
                    pass
                break
            time.sleep(0.1)
            print('Received.')
        try:
            self.destroy()
            self.quit()
        except RuntimeError:
            pass
        print('quited!')

    def run(self):
        threading.Thread(name='connect_and_receive', target=self.connect_receive).start()

    def send_msg(self, s_msg, silent=False):
        s_msg = s_msg.strip()
        if s_msg not in (' ', '\n'):
            # try:
            #     self.connection.send(s_msg)
            # except:
            #     print("Error! Message not send!")
            #     self.print_msg("Error! Message not send!")
            self.connection.sendall(bytes(s_msg, 'utf8'))
            if not silent:
                self.print_msg('我 >>> ' + s_msg)


if __name__ == "__main__":
    restart = False

    while 1:
        master = None
        server = None
        print('new round')
        print(threading.active_count())
        master = tkinter.Tk()
        # master.resizable(0, 0)
        server = ClientUI(master)
        server.settings()

        def connect(s):
            time.sleep(1)
            print('server starts here')
            print(threading.current_thread())
            s.connect_receive()

        print('starting server')
        try:
            server.start()
        except tkinter.TclError:
            print('User closed!')
            break
        print('connecting...')
        server.flags['restart'] = False
        threading.Thread(name='run_server', target=connect, args=(server,)).start()
        master.title('Chat Room')
        server.mainloop()
        server.connection.close()
        restart = server.flags['restart']
        print('window closed!')
        try:
            master.destroy()
        except tkinter.TclError:
            pass
        if not restart:
            break
    print('over!!!')
